﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NETMovie.Entities;
using System.Data;

namespace NETMovie.Repositories.EF
{
    public class TransactionRepository : AbstractRepository, ITransactionRepository
    {
        public TransactionRepository()
        {
            base.Initialize();
        }

        public Transaction GetOpenTransaction(string username)
        {
            User dbUser = cntx.Users.FirstOrDefault(m => m.UserName == username);
            if (dbUser == null)
                throw new UserErrorException(Errors.NO_USER_FOUND);

            List<Transaction> transactions = cntx.Transactions.Where(m => !m.IsPaid && m.User.UserName == username).OrderByDescending(m => m.TransactionId).ToList();
            if (transactions == null || transactions.Count == 0)
                return null;

            return transactions[0];
        }

        public Transaction CreateTransaction(string username)
        {
            User dbUser = cntx.Users.FirstOrDefault(m => m.UserName == username);
            if (dbUser == null)
                throw new UserErrorException(Errors.NO_USER_FOUND);

            Transaction trans = new Transaction();
            trans.CreateDate = DateTime.Now;
            trans.GST = Constants.GST;
            trans.IsPaid = false;
            trans.TotalAmount = 0;
            trans.TransactionDate = DateTime.Now;
            trans.TransactionNo = Guid.NewGuid().ToString();
            trans.User = dbUser;

            cntx.AddToTransactions(trans);
            cntx.SaveChanges();

            if (trans.MovieRentals != null && trans.MovieRentals.Count > 0)
            {
                MovieRental[] rentals = trans.MovieRentals.ToArray();
            }

            return trans;
        }

        public MovieRental GetRental(int rentalID)
        {
            MovieRental rental = cntx.MovieRentals.FirstOrDefault(m => m.MovieRentalId == rentalID);
            return rental;
        }

        public bool RentMovie(int transactionID, int movieId)
        {
            Transaction dbTrans = cntx.Transactions.FirstOrDefault(m => m.TransactionId == transactionID);
            if (dbTrans == null)
                throw new UserErrorException(Errors.NO_TRANS_FOUND);

            Movie dbMovie = cntx.Movies.FirstOrDefault(m => m.MovieId == movieId);
            if (dbMovie == null)
                throw new UserErrorException(Errors.INVALID_MOVIE);

            MovieRental rental = new MovieRental();
            rental.Amount = (dbMovie.IsPremium) ? Constants.PREMIUM_PRICE : Constants.STANDARD_PRICE;
            rental.EndDate = DateTime.Now.AddDays(Constants.NUM_RENTAL_DAYS);
            rental.IssueDate = DateTime.Now;
            rental.Movie = dbMovie;
            rental.ReturnDate = null;

            dbTrans.MovieRentals.Add(rental);
            dbTrans.User.Rentals.Add(rental);

            cntx.SaveChanges();

            return true;
        }

        public bool UnrentMovie(int rentalId)
        {
            MovieRental rental = cntx.MovieRentals.FirstOrDefault(m => m.MovieRentalId == rentalId);
            if (rental == null)
                throw new UserErrorException(Errors.NO_OPEN_RENTAL_FOUND);

            Transaction dbTrans = cntx.Transactions.FirstOrDefault(m => m.TransactionId == rental.Transaction.TransactionId);
            dbTrans.MovieRentals.Remove(rental);
            dbTrans.User.Rentals.Remove(rental);
            cntx.MovieRentals.DeleteObject(rental);
            
            cntx.SaveChanges();

            return true;
        }

        public Transaction GetTransaction(int transactionID)
        {
            Transaction dbTrans = cntx.Transactions.FirstOrDefault(m => m.TransactionId == transactionID);

            if (dbTrans.MovieRentals == null || dbTrans.MovieRentals.Count == 0)
                return dbTrans;

            MovieRental[] rentals = dbTrans.MovieRentals.ToArray();
            for (int i = 0; i < rentals.Length; i++)
            {
                Movie movie = rentals[i].Movie;
            }

            return dbTrans;
        }

        public bool Checkout(int transactionID, decimal amount)
        {
            Transaction dbTrans = cntx.Transactions.FirstOrDefault(m => m.TransactionId == transactionID);
            dbTrans.IsPaid = true;
            dbTrans.TotalAmount = amount;

            cntx.SaveChanges();
            return true;
        }

        public bool ReturnMovie(int rentalId)
        {
            MovieRental rental = cntx.MovieRentals.FirstOrDefault(m => m.MovieRentalId == rentalId);
            if (rental == null || rental.ReturnDate != null)
                throw new UserErrorException(Errors.NO_OPEN_RENTAL_FOUND);

            Transaction dbTrans = cntx.Transactions.FirstOrDefault(m => m.TransactionId == rental.Transaction.TransactionId);
            if (dbTrans == null)
                throw new UserErrorException(Errors.NO_TRANS_FOUND);

            rental.ReturnDate = DateTime.Now;

            cntx.SaveChanges();
            return true;
        }

        public MovieRental[] GetOpenRentals(string username)
        {
            User dbUser = cntx.Users.FirstOrDefault(m => m.UserName == username);
            if (dbUser == null)
                throw new UserErrorException(Errors.NO_USER_FOUND);

            if (dbUser.Rentals == null)
                return null;

            IEnumerable<MovieRental> rentals = dbUser.Rentals.Where(m => m.ReturnDate == null);
            if (rentals == null)
                return null;

            MovieRental[] allRentals = rentals.OrderBy(m => m.EndDate).ToArray();
            for (int i = 0; i < allRentals.Length; i++)
            {
                Movie movie = allRentals[i].Movie;
            }

            return allRentals;
        }

        public MovieRental[] GetDueRentals(string username)
        {
            User dbUser = cntx.Users.FirstOrDefault(m => m.UserName == username);
            if (dbUser == null)
                throw new UserErrorException(Errors.NO_USER_FOUND);

            if (dbUser.Rentals == null)
                return null;

            IEnumerable<MovieRental> rentals = dbUser.Rentals.Where(m => m.EndDate.CompareTo(DateTime.Now) < 0 && m.ReturnDate == null);
            if (rentals == null)
                return null;

            MovieRental[] allRentals = rentals.OrderBy(m => m.EndDate).ToArray();
            for (int i = 0; i < allRentals.Length; i++)
            {
                Movie movie = allRentals[i].Movie;
            }

            return allRentals;
        }

        public MovieRental[] GetActiveRentals(string username)
        {
            User dbUser = cntx.Users.FirstOrDefault(m => m.UserName == username);
            if (dbUser == null)
                throw new UserErrorException(Errors.NO_USER_FOUND);

            if (dbUser.Rentals == null)
                return null;

            IEnumerable<MovieRental> rentals = dbUser.Rentals.Where(m => m.EndDate != null && m.ReturnDate == null && m.Transaction.IsPaid == true);
            if (rentals == null)
                return null;

            MovieRental[] allRentals = rentals.OrderBy(m => m.EndDate).ToArray();
            for (int i = 0; i < allRentals.Length; i++)
            {
                Movie movie = allRentals[i].Movie;
            }

            return allRentals;
        }


        public DataTable GetProfitableUsers(string title, DateTime startDate, DateTime endDate)
        {
            throw new NotImplementedException();
        }
    }
}
